package Helpers;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import DALFacades.IFacade;

public class ApplicationConfiguration {
	
	private static final class Nested
    {
        static final ApplicationConfiguration _instance = new ApplicationConfiguration();
    }
	 
	private ApplicationConfiguration()
	{
		CurrentConfigXML = LoadXML("webapps/JavaCloud/AppConfig/ApplicationConfiguration.xml");
        CurrentLayoutXML = LoadXML("webapps/JavaCloud/AppConfig/Layouts.xml");
        CurrentWeatherConfigXML = LoadXML("webapps/JavaCloud/AppConfig/WeatherConfiguration.xml");
        CurrentMetaSchemaXML = LoadXML("webapps/JavaCloud/AppConfig/MetaSchema.xml");
        CurrentSACGroupXML = LoadXML("webapps/JavaCloud/AppConfig/SACConfig/Groups.xml");
        CurrentRedirectXML = LoadXML("webapps/JavaCloud/AppConfig/RedirectorConfig/RedirectorConfig.xml");      
	}

    public static ApplicationConfiguration getInstance()
    {
         return Nested._instance;
    }
    
    private Document CurrentConfigXML;
    private Document CurrentLayoutXML;
    private Document CurrentWeatherConfigXML;
    private Document CurrentMetaSchemaXML;
    private Document CurrentSACGroupXML;
    private Document CurrentRedirectXML;
    
    public Document getCurrentConfigXML() { return CurrentConfigXML; }
    public Document getCurrentLayoutXML() { return CurrentLayoutXML; }
    public Document getCurrentWeatherConfigXML() { return CurrentWeatherConfigXML; }
    public Document getCurrentMetaSchemaXML() { return CurrentMetaSchemaXML; }
    public Document getCurrentSACGroupXML() { return CurrentSACGroupXML; }
    public Document getCurrentRedirectXML() { return CurrentRedirectXML; }
    
    private Document LoadXML(String path)
    {
    	ApplicationLogger.getInstance().LOG.info("XML Document loading from: " + path);
    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		Document doc = db.newDocument();
		try {
			doc = db.parse(new File(path));
		} catch (SAXException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		} catch (IOException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
        return doc;
    }
    
    public Map<String, String> getTargetInCurrentRedirectorBySource(String source)
    {
    	Map<String, String> pagePropertyObject = new HashMap<String, String>();
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression target_expr = null;
		XPathExpression target_desc_expr = null;
		
		try {
			 target_expr = xpath.compile(String.format("//redirectorItem[@id='%1$s']/target/text()", source));
			 target_desc_expr = xpath.compile(String.format("//redirectorItem[@id='%1$s']/description/text()", source));
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String target = "";
		String target_desc = "";
		try {
			target = (String) target_expr.evaluate(CurrentRedirectXML, XPathConstants.STRING);
			target_desc = (String) target_desc_expr.evaluate(CurrentRedirectXML, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}

		pagePropertyObject.put("target", target);
		pagePropertyObject.put("description", target_desc);
		
		return pagePropertyObject;
    }
    
    public void LoadCurrentFacade()
    {
    	Context ctx = null;
    	 try {
 			ctx = new InitialContext();
     	 } catch (NamingException e) {
     		 ApplicationLogger.getInstance().LOG.error(e.getMessage());
     	 }
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression facade_expr = null;
		try {
			 facade_expr = xpath.compile("//DataFacade/text()");
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String facade = "";
		try {
			facade = (String) facade_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		ApplicationLogger.getInstance().LOG.info("Current facade name is " + facade);
		
		if(facade != "")
		{
			try {
				ApplicationLogger.getInstance().LOG.info("Trying to invoke facade name " + facade);
				Class<IFacade> facadeType = (Class<IFacade>) Class.forName("DALFacades." + facade);
				
				
				Constructor<?> ctr = null;
				IFacade facadeObj = null;
				try {
					ctr = facadeType.getConstructor();
				} catch (SecurityException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				} catch (NoSuchMethodException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				}
				
				try {
					facadeObj = (IFacade) ctr.newInstance();
				} catch (IllegalArgumentException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				} catch (InstantiationException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				} catch (IllegalAccessException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				} catch (InvocationTargetException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				}
	
				ApplicationLogger.getInstance().LOG.info("Invoked facade name " + facadeObj.getClass().getName());
				try {
					ctx.bind("Facade", facadeObj);
					ApplicationLogger.getInstance().LOG.info("Facade name is " + facade + " binded");
				} catch (NamingException e) {
					ApplicationLogger.getInstance().LOG.error("ERROR: " + e.getMessage());
				}
			} catch (ClassNotFoundException e) {
				ApplicationLogger.getInstance().LOG.error(e.getMessage());
			}
		}	
    }
    
    public void LoadCurrentBackward()
    {
    	Context ctx = null;
    	 try {
 			ctx = new InitialContext();
     	 } catch (NamingException e) {
     		 ApplicationLogger.getInstance().LOG.error(e.getMessage());
     	 }
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression backward_expr = null;
		try {
			backward_expr = xpath.compile("//Backward/text()");
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String backward= "";
		try {
			backward = (String) backward_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		ApplicationLogger.getInstance().LOG.info("Current backward: " + backward);
		
		if(backward != "")
		{
			try {
				Class<?> backwardObj = (Class<?>) Class.forName(backward);
				try {
					ctx.bind("Backward", backwardObj);
				} catch (NamingException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				}
			} catch (ClassNotFoundException e) {
				ApplicationLogger.getInstance().LOG.error(e.getMessage());
			}
		}
    }
    
    public Map<String, String> getDBSettings(){
    	Map<String, String> result = new HashMap<String, String>();
    	
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression driverClass_expr = null;
		XPathExpression connectionUrl_expr = null;
		XPathExpression login_expr = null;
		XPathExpression password_expr = null;
		try {
			driverClass_expr = xpath.compile("//root/DBSetting/DriverClass/text()");
			connectionUrl_expr = xpath.compile("//root/DBSetting/ConnectionUrl/text()");
			login_expr = xpath.compile("//root/DBSetting/Login/text()");
			password_expr = xpath.compile("//root/DBSetting/Password/text()");		
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String driverClass = "";
		String connectionUrl = "";
		String login = "";
		String password = "";
		try {
			driverClass = (String) driverClass_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
			connectionUrl = (String) connectionUrl_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
			login = (String) login_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
			password = (String) password_expr.evaluate(CurrentConfigXML, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		ApplicationLogger.getInstance().LOG.info("Driver Class: " + driverClass);
		ApplicationLogger.getInstance().LOG.info("Connection Url: " + connectionUrl);
		ApplicationLogger.getInstance().LOG.info("Login: " + login);
		ApplicationLogger.getInstance().LOG.info("Password: " + password);
    	
		result.put("DriverClass", driverClass);
		result.put("ConnectionUrl", connectionUrl);
		result.put("Login", login);
		result.put("Password", password);
		
    	return result;
    }
    
    public String GetWeatherFeedURI()
    {
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression feedURI_expr = null;
		try {
			 feedURI_expr = xpath.compile("//FeedURI/text()");
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String feedURI= "";
		try {
			feedURI = (String) feedURI_expr.evaluate(CurrentWeatherConfigXML, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		ApplicationLogger.getInstance().LOG.info("Feed: " + feedURI);
        return feedURI;
    }
    
    public String GetCurrentWeatherImgPathByName(String name)
    {
    	XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression item_path_day_expr = null;
		XPathExpression item_path_night_expr = null;
		XPathExpression dayFrom_expr = null;
		XPathExpression dayTo_expr = null;
		
		try {
			item_path_day_expr = xpath.compile(String.format("//WeatherMaper/Item[@name='%1$s']/@pathDay", name));
			item_path_night_expr = xpath.compile(String.format("//WeatherMaper/Item[@name='%1$s']/@pathNight", name));
			dayFrom_expr = xpath.compile("//DayDuration/@from");
			dayTo_expr = xpath.compile("//DayDuration/@to");
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}

		NodeList item_path_day = null;
		NodeList item_path_night = null;
		NodeList dayFrom = null;
		NodeList dayTo = null;
		
		try {
			item_path_day = (NodeList) item_path_day_expr.evaluate(CurrentWeatherConfigXML, XPathConstants.NODESET);
			item_path_night = (NodeList) item_path_night_expr.evaluate(CurrentWeatherConfigXML, XPathConstants.NODESET);
			dayFrom = (NodeList) dayFrom_expr.evaluate(CurrentWeatherConfigXML, XPathConstants.NODESET);
			dayTo = (NodeList) dayTo_expr.evaluate(CurrentWeatherConfigXML, XPathConstants.NODESET);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
		Date dateDayTo = new Date();
		Date dateDayFrom = new Date();
		
		try {
			dateDayFrom = sdf.parse(dayFrom.item(0).getNodeValue());
			dateDayTo = sdf.parse(dayTo.item(0).getNodeValue());
		} catch (DOMException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		} catch (ParseException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		String result = "";
		long now = (new Date()).getTime();
		if(dateDayFrom.getTime() < now && now < dateDayTo.getTime())
        {
            result = item_path_day.item(0).getNodeValue();
        }
        else
        {
            result = item_path_night.item(0).getNodeValue();
        }
		ApplicationLogger.getInstance().LOG.info("Weather img_path: " + result);
        return result;
    }

	public Map<String, String[]> GetLayout(String alias) {
		
		XPathFactory xpf = XPathFactory.newInstance();
		XPath xpath = xpf.newXPath();
		
		 String _alias = alias;
         if (alias == "")
         {
        	 XPathExpression alias_expr = null;
        	 try {
				alias_expr = xpath.compile("//Layout[@IsDefault='true']/@Alias");
			} catch (XPathExpressionException e) {
				ApplicationLogger.getInstance().LOG.error(e.getMessage());
			}
             try {
				_alias = ((Node)alias_expr.evaluate(CurrentLayoutXML, XPathConstants.NODE)).getNodeValue();
			} catch (XPathExpressionException e) {
				ApplicationLogger.getInstance().LOG.error(e.getMessage());
			}
         }
         
		XPathExpression ctrl_lst_expr = null;
		try {
			ctrl_lst_expr = xpath.compile(String.format("//Layout[@Alias='%1$s']/Control", _alias));
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		} 
		
		NodeList ctrl_lst = null;

		try {
			ctrl_lst = (NodeList) ctrl_lst_expr.evaluate(CurrentLayoutXML, XPathConstants.NODESET);
		} catch (XPathExpressionException e) {
			ApplicationLogger.getInstance().LOG.error(e.getMessage());
		}
		
		Map<String, String[]> result = new HashMap<String, String[]>();
		String[] attrs = new String[3];
		for (int i = 0; i < ctrl_lst.getLength(); i++) {
			attrs[0] = ctrl_lst.item(i).getAttributes().getNamedItem("Path").getNodeValue();
			Node access = ctrl_lst.item(i).getAttributes().getNamedItem("Access");
			attrs[1] = access == null ? "" : access.getNodeValue();
			Node meta = ctrl_lst.item(i).getAttributes().getNamedItem("MetaSchema");
			attrs[2] = meta == null ? "" : meta.getNodeValue();
			result.put(ctrl_lst.item(i).getAttributes().getNamedItem("Name").getNodeValue(), attrs);
		}
		
		return result;
	}
}
